#include <cstring>
#include <iostream>

#include <fcntl.h>
#include <io.h>
#include <windows.h>

#include "io_exceptions.h"
#include "msvc_io.h"


void recurs_dir(std::string &path, std::vector<filenode> &nodes, long long int &size)
{
    std::string tpath = path + "*";

    WIN32_FIND_DATA FindFileData;
    HANDLE hf = FindFirstFile(tpath.c_str(), &FindFileData);
	
    if (hf != INVALID_HANDLE_VALUE) {
        do {
            if ((FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
                if (strcmp(FindFileData.cFileName, ".") == 0 || strcmp(FindFileData.cFileName, "..") == 0) {
                    continue;
                }

                recurs_dir(path + FindFileData.cFileName + '\\', nodes, size);
                continue;
            }

            long long int tsize = FindFileData.nFileSizeHigh;
            tsize <<= 32;
            tsize += FindFileData.nFileSizeLow;
            size += tsize;
            filenode fnode(path + FindFileData.cFileName, tsize);
            nodes.push_back(fnode);
        } while (FindNextFile(hf, &FindFileData) != 0);
    }
    FindClose(hf);
}


void calc_hash(std::string & path, unsigned char * data)
{
    int fd = _open(path.c_str(), _O_RDONLY);
    try {
        if (fd < 0) {
            throw io_exceptions::read_file_exception(path);
        }
    } catch (io_exceptions::read_file_exception e) {
        std::cerr << e.msg << std::endl;
        return;
    }
    
    SHA512_CTX sha512_content;
    SHA512_Init(&sha512_content);

    char buf[BLOCK_SIZE];

    while (true) {
        size_t nr = _read(fd, buf, BLOCK_SIZE);
        if (nr <= 0) {
            break;
        }
        SHA512_Update(&sha512_content, buf, nr);
    }

    SHA512_Final(data, &sha512_content);
    _close(fd);
}    
